
#  Created by Tom Lichtenberg on 2009-08-08.
#  Copyright (c) 2009 Mu Dynamics. All rights reserved.

require 'rubygems'
require 'uri'
require "libxml"
require 'uuid'

include LibXML

class XML::Document
  
  attr_accessor :uuid, :run_uuid
  # Save the analysis object in XML format to a file. Takes a filename parameter, dir path is global

  def save(filename="analysis.xml")
    f = File.new(filename, File::CREAT|File::TRUNC|File::WRONLY)
    f.write(self.to_s)
    f.close
  end

  # Post the analysis object to the muserver. Shows up as a draft
  def post(username='admin',password='admin')
    xmldoc = nil
    host  = $testbed_ip
    uri = URI.parse("https://#{host}/")
    resp = response = "";
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    begin
	    http.start do |http|
	      req = Net::HTTP::Post.new("/api/v3/templates/import", {"User-Agent" => username})
	      req.basic_auth(username, password)
	      req.body = self.to_s
        $DEBUG and puts self
	      response = http.request(req)
	      resp = response.body
	    end
	    #  XML Document
      if (/<.+>/).match(resp)
        xmldoc = XML::Document.string(resp)
      else
        xmldoc = XML::Document.new
        xmldoc.root = XML::Node.new('err_node', resp)
      end 
    rescue SocketError
	    raise "Host " + host + " nicht erreichbar"
    rescue Exception => e
	    puts "error parsing XML " + e.to_s
    end
    if (xmldoc.nil? || xmldoc.find('*').nil?)
      $DEBUG and puts resp
      return nil
    end
    return xmldoc
  end

  # Export
  def export
    uuid = self.find_first("//analysis").attributes['uuid']
    @api = Mu_Api.new($testbed_ip, "/api/v3")
    doc = @api.request("templates/export?uuid=#{uuid}")
    return doc
  end

  # Run
  def run
    @uuid = self.find_first("//analysis").attributes['uuid']
    unless @uuid
      $DEBUG and puts "no uuid attribute found for this analysis"
      return false
    end 
    @api = Mu_Api.new($testbed_ip)
    doc = @api.request("analysis/run?uuid=#{@uuid}")
    unless doc.find_first("//analysis").nil?
      @run_uuid = doc.find_first("//analysis").attributes['uuid']
      $DEBUG and puts "Running UUID: #{@run_uuid}"
      self.find_first("//analysis").attributes['run_uuid'] = @run_uuid
    end
    return doc
  end

  # Stop analysis. UUID taken from analysis, or supplied
  def stop
    run_uuid = self.find_first("//analysis").attributes['run_uuid']
    return false unless run_uuid
    @api = Mu_Api.new($testbed_ip)
    doc = @api.request("analysis/stop?uuid=#{run_uuid}")
    return doc
  end
  
  # pause analysis. UUID taken from analysis, or supplied
  def pause
    run_uuid = self.find_first("//analysis").attributes['run_uuid']
    return false unless run_uuid
    @api = Mu_Api.new($testbed_ip)
    doc = @api.request("analysis/pause?uuid=#{run_uuid}")
    return doc
  end
  
  # resume analysis. UUID taken from analysis, or supplied
  def resume
    run_uuid = self.find_first("//analysis").attributes['run_uuid']
    return false unless run_uuid
    @api = Mu_Api.new($testbed_ip)
    doc = @api.request("analysis/resume?uuid=#{run_uuid}")
    return doc
  end
  

  # fetch status for analysis. 
  def status
    run_uuid = self.find_first("//analysis").attributes['run_uuid']
    return false unless run_uuid
    @api = Mu_Api.new($testbed_ip)
    doc = @api.request("analysis/status?uuid=#{run_uuid}")
    return doc
  end

  # fetch status for analysis. 
  def faults
    run_uuid = self.find_first("//analysis").attributes['run_uuid']
    return false unless run_uuid
    @api = Mu_Api.new($testbed_ip)
    doc = @api.request("analysis/getFaultList?uuid=#{run_uuid}",true)
    check_response_for_errors(doc, "err_node", "getFaultList")
    return doc
  end

  # poll while the analysis status is RUNNING, or any other match string
  # returns the final status after polling fails to find match or times out
  def poll_while(match="RUNNING|QUEUED",timeout="300", fault_limit=0, logger_file="")
    puts "poll_while called with fault_limit = #{fault_limit}"
    run_uuid = self.find_first("//analysis").attributes['run_uuid']
    puts "poll_while using run_uuid #{run_uuid}"
    return false unless run_uuid
    @api = Mu_Api.new($testbed_ip)
    status = false
    interval = 10  # 5
    iterations = (timeout.to_i/interval).to_i
    iterations.times do |i|

      # get fault count. if greater or equal than threshhold then return "fault limit reached"
      # caller needs to check that return value
      unless fault_limit == 0
        if logger_file == ""
          puts "calling getFaults"
          @soap_api = Mu_Api.new($testbed_ip, "/rai/rest/mu")
          faults = @soap_api.request("getFaults?uuid=#{run_uuid}")
          puts faults
          fault_count = faults.find('//tba_fault').length
          puts "fault_count = #{fault_count}"
          if fault_count >= fault_limit
            return "fault limit reached"
          end
        else # poll logger file
          # grep logger file for count of 'Fault Found'
          fault_count = `grep -c "Fault Found" #{logger_file}`
          puts "fault_count = #{fault_count}"
          if fault_count.to_i >= fault_limit
            return "fault limit reached"
          end
        end
      end

      #puts "calling status"
      doc = @api.request("analysis/status?uuid=#{run_uuid}")
      #puts doc
      status = doc.root.find_first("status").content
      return status unless status =~ /(#{match})/
      
      sleep interval
    end
    return status
    
  end

end

